home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / ck5a189s / ckucon.c < prev    next >
C/C++ Source or Header  |  1993-06-04  |  43KB  |  1,366 lines

  1. char *connv = "CONNECT Command for UNIX, 5A(054) 26 May 93";
  2.  
  3. /*  C K U C O N  --  Dumb terminal connection to remote system, for UNIX  */
  4. /*
  5.   Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  6.   Columbia University Academic Information Systems, New York City.
  7.  
  8.   Copyright (C) 1985, 1993, Trustees of Columbia University in the City of New
  9.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  10.   sold for profit as a software product itself, nor may it be included in or
  11.   distributed with commercial products or otherwise distributed by commercial
  12.   concerns to their clients or customers without written permission of the
  13.   Office of Kermit Development and Distribution, Columbia University.  This
  14.   copyright notice must not be removed, altered, or obscured.
  15. */
  16. #include "ckcdeb.h"            /* Common things first */
  17.  
  18. #ifdef NEXT
  19. #undef NSIG
  20. #include <sys/wait.h>            /* For wait() */
  21. #endif /* NEXT */
  22.  
  23. #include <signal.h>            /* Signals */
  24. #include <errno.h>            /* Error numbers */
  25.  
  26. #ifdef ZILOG                /* Longjumps */
  27. #include <setret.h>
  28. #else
  29. #include <setjmp.h>
  30. #endif /* ZILOG */
  31.  
  32. /* Kermit-specific includes */
  33.  
  34. #include "ckcasc.h"            /* ASCII characters */
  35. #include "ckcker.h"            /* Kermit things */
  36. #include "ckucmd.h"            /* For xxesc() prototype */
  37. #include "ckcnet.h"            /* Network symbols */
  38. #ifndef NOCSETS
  39. #include "ckcxla.h"            /* Character set translation */
  40. #endif /* NOCSETS */
  41.  
  42. /* Internal function prototypes */
  43.  
  44. _PROTOTYP( VOID doesc, (char) );
  45. _PROTOTYP( VOID logchar, (char) );
  46. _PROTOTYP( int hconne, (void) );
  47. _PROTOTYP( VOID shomdm, (void) );
  48.  
  49. #ifndef SIGUSR1                /* User-defined signals */
  50. #define SIGUSR1 30
  51. #endif /* SIGUSR1 */
  52.  
  53. #ifndef SIGUSR2
  54. #define SIGUSR2 31
  55. #endif /* SIGUSR2 */
  56.  
  57. /* External variables */
  58.  
  59. extern int local, escape, duplex, parity, flow, seslog, sessft, debses,
  60.  mdmtyp, ttnproto, cmask, cmdmsk, network, nettype, deblog, sosi, tnlm,
  61.  xitsta, what, ttyfd, quiet, backgrd, pflag, tt_crd, tn_nlm, ttfdflg;
  62. extern long speed;
  63. extern char ttname[], sesfil[], myhost[], *ccntab[];
  64.  
  65. #ifndef NOSETKEY            /* Keyboard mapping */
  66. extern KEY *keymap;            /* Single-character key map */
  67. extern MACRO *macrotab;            /* Key macro pointer table */
  68. static MACRO kmptr = NULL;        /* Pointer to current key macro */
  69. #endif /* NOSETKEY */
  70.  
  71. /* Global variables local to this module */
  72.  
  73. static int quitnow = 0,            /* <esc-char>Q was typed */
  74.   dohangup = 0,                /* <esc-char>H was typed */
  75.   sjval = 0,                /* Setjump return value */
  76.   goterr = 0,                /* I/O error flag */
  77. #ifndef SUNX25
  78.   active = 0,                /* Lower fork active flag */
  79. #endif /* SUNX25 */
  80.   inshift = 0,                /* SO/SI shift states */
  81.   outshift = 0;
  82.  
  83. static char kbuf[10], *kbp;        /* Keyboard buffer & pointer */
  84. static PID_T parent_id = (PID_T)0;    /* Process id of keyboard fork */
  85.  
  86. static char *ibp;            /* Input buffer pointer */
  87. static int ibc = 0;            /* Input buffer count */
  88. #ifdef pdp11
  89. #define IBUFL 1536            /* Input buffer length */
  90. #else
  91. #define IBUFL 4096
  92. #endif /* pdp11 */
  93.  
  94. static char *obp;            /* Output buffer pointer */
  95. static int obc = 0;            /* Output buffer count */
  96. #ifndef OXOS
  97. #define OBUFL 1024            /* Output buffer length */
  98. #else /* OXOS */
  99. #define OBUFL IBUFL
  100. #endif /* OXOS */
  101.  
  102. #define TMPLEN 200            /* Temporary message buffer length */
  103. #ifdef DYNAMIC
  104. static char *ibuf = NULL, *obuf = NULL, *temp = NULL; /* Buffers */
  105. #else
  106. static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN];
  107. #endif /* DYNAMIC */
  108.  
  109. /* SunLink X.25 items */
  110.  
  111. #ifdef SUNX25
  112. static char *p;                /* General purpose pointer */
  113. char x25ibuf[MAXIX25];            /* Input buffer */
  114. char x25obuf[MAXOX25];            /* Output buffer */
  115. int active = 0;                /* Lower fork active flag */
  116. int ibufl;                /* Length of input buffer */
  117. int obufl;                /* Length of output buffer */
  118. unsigned char tosend = 0;
  119. int linkid, lcn;
  120. static int dox25clr = 0;
  121. CHAR padparms[MAXPADPARMS+1];
  122. static int padpipe[2];            /* Pipe descriptor to pass PAD parms */
  123. #endif /* SUNX25 */
  124.  
  125. /* Character-set items */
  126.  
  127. #ifndef NOCSETS
  128. #ifdef CK_ANSIC /* ANSI C prototypes... */
  129. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
  130. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
  131. static CHAR (*sxo)(CHAR);    /* Local translation functions */
  132. static CHAR (*rxo)(CHAR);    /* for output (sending) terminal chars */
  133. static CHAR (*sxi)(CHAR);    /* and for input (receiving) terminal chars. */
  134. static CHAR (*rxi)(CHAR);
  135. #else /* Not ANSI C... */
  136. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();    /* Character set */
  137. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])();    /* translation functions. */
  138. static CHAR (*sxo)();        /* Local translation functions */
  139. static CHAR (*rxo)();        /* for output (sending) terminal chars */
  140. static CHAR (*sxi)();        /* and for input (receiving) terminal chars. */
  141. static CHAR (*rxi)();
  142. #endif /* CK_ANSIC */
  143. extern int language;        /* Current language. */
  144. static int langsv;        /* For remembering language setting. */
  145. extern struct csinfo fcsinfo[]; /* File character set info. */
  146. extern int tcsr, tcsl;        /* Terminal character sets, remote & local. */
  147. static int tcs;            /* Intermediate ("transfer") character set. */
  148.  
  149. #ifndef NOESCSEQ
  150. /*
  151.   As of edit 178, the CONNECT command will skip past ANSI escape sequences
  152.   to avoid translating the characters within them.  This allows the CONNECT
  153.   command to work correctly when connected to a remote host that uses a
  154.   7-bit ISO 646 national character set, in which characters like '[' would
  155.   normally be translated into accented characters, ruining the terminal's
  156.   interpretation (and generation) of escape sequences.
  157.  
  158.   Escape sequences of non-ANSI/ISO-compliant terminals are not handled.
  159. */
  160. #ifndef SKIPESC
  161. #define SKIPESC
  162. #endif /* SKIPESC */
  163. /*
  164.   States for the escape-sequence recognizer.
  165. */
  166. #define ES_NORMAL 0            /* Normal, not in escape sequence */
  167. #define ES_GOTESC 1            /* Current character is ESC */
  168. #define ES_ESCSEQ 2            /* Inside an escape sequence */
  169. #define ES_GOTCSI 3            /* Inside a control sequence */
  170. #define ES_STRING 4            /* Inside DCS,OSC,PM, or APC string */
  171. #define ES_TERMIN 5            /* 1st char of string terminator */
  172.  
  173. static int
  174.   skipesc = 0,                /* Skip over ANSI escape sequences */
  175.   inesc = ES_NORMAL;            /* State of sequence recognizer */
  176. /*
  177.   ANSI escape sequence handling.  Only the 7-bit form is treated, because
  178.   translation is not a problem in the 8-bit environment, in which all GL
  179.   characters are ASCII and no translation takes place.  So we don't check
  180.   for the 8-bit single-character versions of CSI, DCS, OSC, APC, or ST.
  181.   Here is the ANSI sequence recognizer state table, followed by the code
  182.   that implements it.
  183.  
  184.   Definitions:
  185.     CAN = Cancel                       01/08         Ctrl-X
  186.     SUB = Substitute                   01/10         Ctrl-Z
  187.     DCS = Device Control Sequence      01/11 05/00   ESC P
  188.     CSI = Control Sequence Introducer  01/11 05/11   ESC [
  189.     ST  = String Terminator            01/11 05/12   ESC \
  190.     OSC = Operating System Command     01/11 05/13   ESC ]
  191.     PM  = Privacy Message              01/11 05/14   ESC ^
  192.     APC = Application Program Command  01/11 05/15   ESC _
  193.  
  194.   ANSI escape sequence recognizer:
  195.  
  196.     State    Input  New State  ; Commentary
  197.  
  198.     NORMAL   (start)           ; Start in NORMAL state
  199.  
  200.     (any)    CAN    NORMAL     ; ^X cancels
  201.     (any)    SUB    NORMAL     ; ^Z cancels
  202.  
  203.     NORMAL   ESC    GOTESC     ; Begin escape sequence
  204.     NORMAL   other             ; NORMAL control or graphic character
  205.  
  206.     GOTESC   ESC               ; Start again
  207.     GOTESC   [      GOTCSI     ; CSI
  208.     GOTESC   P      STRING     ; DCS introducer, consume through ST
  209.     GOTESC   ]      STRING     ; OSC introducer, consume through ST
  210.     GOTESC   ^      STRING     ; PM  introducer, consume through ST
  211.     GOTESC   _      STRING     ; APC introducer, consume through ST
  212.     GOTESC   0..~   NORMAL     ; 03/00 through 17/14 = Final character
  213.     GOTESC   other  ESCSEQ     ; Intermediate or ignored control character
  214.  
  215.     ESCSEQ   ESC    GOTESC     ; Start again
  216.     ESCSEQ   0..~   NORMAL     ; 03/00 through 17/14 = Final character
  217.     ESCSEQ   other             ; Intermediate or ignored control character
  218.  
  219.     GOTCSI   ESC    GOTESC     ; Start again
  220.     GOTCSI   @..~   NORMAL     ; 04/00 through 17/14 = Final character
  221.     GOTCSI   other             ; Intermediate char or ignored control char
  222.  
  223.     STRING   ESC    TERMIN     ; Maybe have ST
  224.     STRING   other             ; Consume all else
  225.  
  226.     TERMIN   \      NORMAL     ; End of string
  227.     TERMIN   other  STRING     ; Still in string
  228. */
  229. /*
  230.   chkaes() -- Check ANSI Escape Sequence.
  231.   Call with EACH character in input stream.
  232.   Sets global inesc variable according to escape sequence state.
  233. */
  234. VOID
  235. #ifdef CK_ANSIC
  236. chkaes(char c)
  237. #else
  238. chkaes(c) char c;
  239. #endif /* CK_ANSIC */
  240. /* chkaes */ {
  241.  
  242.     if (c == CAN || c == SUB)        /* CAN and SUB cancel any sequence */
  243.       inesc = ES_NORMAL;
  244.     else                /* Otherwise */
  245.       switch (inesc) {            /* enter state switcher */
  246.  
  247.     case ES_NORMAL:            /* NORMAL state */
  248.       if (c == ESC)            /* Got an ESC */
  249.         inesc = ES_GOTESC;        /* Change state to GOTESC */
  250.       break;            /* Otherwise stay in NORMAL state */
  251.  
  252.     case ES_GOTESC:            /* GOTESC state */
  253.       if (c == '[')            /* Left bracket after ESC is CSI */
  254.         inesc = ES_GOTCSI;        /* Change to GOTCSI state */
  255.       else if (c > 057 && c < 0177)    /* Final character '0' thru '~' */
  256.         inesc = ES_NORMAL;        /* Back to normal */
  257.       else if (c == 'P' || (c > 0134 && c < 0140)) /* P, [, ^, or _ */
  258.         inesc = ES_STRING;        /* Switch to STRING-absorption state */
  259.       else if (c != ESC)        /* ESC in an escape sequence... */
  260.         inesc = ES_ESCSEQ;        /* starts a new escape sequence */
  261.       break;            /* Intermediate or ignored ctrl char */
  262.  
  263.     case ES_ESCSEQ:            /* ESCSEQ -- in an escape sequence */
  264.       if (c > 057 && c < 0177)    /* Final character '0' thru '~' */
  265.         inesc = ES_NORMAL;        /* Return to NORMAL state. */
  266.       else if (c == ESC)        /* ESC ... */
  267.         inesc = ES_GOTESC;        /* starts a new escape sequence */
  268.       break;            /* Intermediate or ignored ctrl char */
  269.  
  270.     case ES_GOTCSI:            /* GOTCSI -- In a control sequence */
  271.       if (c > 077 && c < 0177)    /* Final character '@' thru '~' */
  272.         inesc = ES_NORMAL;        /* Return to NORMAL. */
  273.       else if (c == ESC)        /* ESC ... */
  274.         inesc = ES_GOTESC;        /* starts over. */
  275.       break;            /* Intermediate or ignored ctrl char */
  276.  
  277.     case ES_STRING:            /* Inside a string */
  278.       if (c == ESC)            /* ESC may be 1st char of terminator */
  279.         inesc = ES_TERMIN;        /* Go see. */
  280.       break;            /* Absorb all other characters. */
  281.  
  282.     case ES_TERMIN:            /* May have a string terminator */
  283.       if (c == '\\')        /* which must be backslash */
  284.         inesc = ES_NORMAL;        /* If so, back to NORMAL */
  285.       else                /* Otherwise */
  286.         inesc = ES_STRING;        /* Back to string absorption. */
  287.       }
  288. }
  289. #endif /* NOESCSEQ */
  290. #endif /* NOCSETS */
  291.  
  292. /* Connect state parent/child communication signal handlers */
  293.  
  294. static jmp_buf con_env;         /* Environment pointer for connect errors */
  295. /*
  296.   Note: Some C compilers (e.g. Cray UNICOS) interpret the ANSI C standard
  297.   about setjmp() in a way that disallows constructions like:
  298.  
  299.     if ((var = setjmp(env)) == 0) ...
  300.  
  301.   which prevents the value returned by longjmp() from being used at all.
  302.   So the following handlers set a global variable instead.
  303. */
  304. static
  305. SIGTYP
  306. conn_int(foo) int foo; {        /* Modem read failure handler, */
  307.     signal(SIGUSR1,SIG_IGN);        /* Disarm the interrupt */
  308.     sjval = 1;                /* Set global variable */
  309.     longjmp(con_env,sjval);        /* Notifies parent process to stop */
  310. }
  311.  
  312. static
  313. SIGTYP
  314. mode_chg(foo) int foo; {
  315.     signal(SIGUSR2,mode_chg);        /* Re-arm the signal immediately. */
  316.  
  317. #ifdef SUNX25                /* X.25 read new params from pipe */
  318.     if (nettype == NET_SX25) {
  319.         read(padpipe[0],padparms,MAXPADPARMS);
  320.         debug(F100,"pad_chg","",0);
  321. /*
  322.   NOTE: we can probably skip this longjmp, just as we do in the "else" case.
  323.   But I don't (yet) have any way to test this.
  324. */
  325.     sjval = 2;            /* Set global variable. */
  326.     longjmp(con_env,sjval);
  327.     debug(F100,"mode_chg X.25","",0);
  328.     } else {
  329. #endif /* SUNX25 */
  330.     duplex = 1 - duplex;        /* Toggle duplex mode. */
  331.     debug(F101,"mode_chg duplex","",duplex);
  332. #ifdef SUNX25
  333.     }
  334. #endif /* SUNX25 */
  335. }
  336.  
  337. /*  C K C P U T C  --  C-Kermit CONNECT Put Character to Screen  */
  338. /*
  339.   Output is buffered to avoid slow screen writes on fast connections.
  340. */
  341. int
  342. ckcputf() {                /* Dump the output buffer */
  343.     int x = 0;
  344.     if (obc > 0)            /* If we have any characters, */
  345.       x = conxo(obc,obuf);        /* dump them, */
  346.     obp = obuf;                /* reset the pointer */
  347.     obc = 0;                /* and the counter. */
  348.     return(x);                /* Return conxo's return code */
  349. }
  350.  
  351. int
  352. ckcputc(c) int c; {
  353.     int x;
  354.  
  355.     *obp++ = c & 0xff;            /* Deposit the character */
  356.     obc++;                /* Count it */
  357.     if (ibc == 0 ||            /* If input buffer about empty */
  358.     obc == OBUFL) {            /* or output buffer full */
  359.     debug(F101,"CKCPUTC obc","",obc);
  360.     x = conxo(obc,obuf);        /* dump the buffer, */
  361.     obp = obuf;            /* reset the pointer */
  362.     obc = 0;            /* and the counter. */
  363.     return(x);            /* Return conxo's return code */
  364.     } else return(0);
  365. }
  366.  
  367. /*  C K C G E T C  --  C-Kermit CONNECT Get Character  */
  368. /*
  369.   Buffered read from communication device.
  370.   Returns the next character, refilling the buffer if necessary.
  371.   On error, returns ttinc's return code (see ttinc() description).
  372.   Dummy argument for compatible calling conventions with ttinc().
  373. */
  374. int
  375. ckcgetc(dummy) int dummy; {
  376.     int c, n;
  377.  
  378.     debug(F101,"CKCGETC 1 ibc","",ibc); /* Log */
  379.     if (ibc < 1) {            /* Need to refill buffer? */
  380.     ibc = 0;            /* Yes, reset count */
  381.     ibp = ibuf;            /* and buffer pointer */
  382.     debug(F100,"CKCGETC 1 calling ttinc(0)","",0); /* Log */
  383.     c = ttinc(0);            /* Read one character, blocking */
  384.     debug(F101,"CKCGETC 1 ttinc(0)","",c); /* Log */
  385.     if (c < 0) {            /* If error, return error code */
  386.         return(c);
  387.     } else {            /* Otherwise, got one character */
  388.         *ibp++ = c;            /* Advance buffer pointer */
  389.         ibc++;            /* and count. */
  390.     }
  391.  
  392.     /* Now quickly read any more that might have arrived */
  393.  
  394.     if ((n = ttchk()) > 0) {    /* Any more waiting? */
  395.         if (n > (IBUFL - ibc))    /* Get them all at once. */
  396.           n = IBUFL - ibc;        /* Don't overflow buffer */
  397.         if ((n = ttxin(n,(CHAR *)ibp)) > 0) {
  398.         ibp += n;        /* Advance pointer */
  399.         ibc += n;        /* and counter */
  400.         } else return(-1);
  401.     }
  402.     debug(F101,"CKCGETC 2 ibc","",ibc); /* Log how many */
  403.     ibp = ibuf;
  404.     }
  405.     c = *ibp++ & 0xff;            /* Get next character from buffer */
  406.     ibc--;                /* Reduce buffer count */
  407.     return(c);                /* Return the character */
  408. }
  409.  
  410. /*  C O N E C T  --  Perform terminal connection  */
  411.  
  412. int
  413. conect() {
  414.     PID_T pid;            /* Process id of child (modem reader) */
  415.     int    n;            /* General purpose counter */
  416.  
  417.     int c;            /* c is a character, but must be signed 
  418.                    integer to pass thru -1, which is the
  419.                    modem disconnection signal, and is
  420.                    different from the character 0377 */
  421.     int c2;            /* A copy of c */
  422.     int csave;            /* Another copy of c */
  423.     int tx;            /* tn_doop() return code */
  424. #ifdef SUNX25
  425.     int i;            /* Worker for X.25 code*/
  426. #endif /* SUNX25 */
  427. #ifdef NETCONN
  428. #ifdef SIGPIPE
  429.     SIGTYP (*sigpiph)() = NULL;
  430. #endif /* SIGPIPE */
  431. #endif /* NETCONN */
  432.  
  433. #ifdef DYNAMIC
  434.     if (!(ibuf = malloc(IBUFL+1))) {    /* Allocate input line buffer */
  435.     printf("Sorry, CONNECT input buffer can't be allocated\n");
  436.     return(0);
  437.     }
  438.     if (!(obuf = malloc(OBUFL+1))) {    /* Allocate input line buffer */
  439.     printf("Sorry, CONNECT output buffer can't be allocated\n");
  440.     free(ibuf);
  441.     return(0);
  442.     }
  443.     if (!(temp = malloc(TMPLEN+1))) {    /* Allocate temporary buffer */
  444.     printf("Sorry, CONNECT temporary buffer can't be allocated\n");
  445.     free(obuf);
  446.     return(0);
  447.     }
  448. #endif /* DYNAMIC */
  449.  
  450.     if (!local) {
  451. #ifdef NETCONN
  452.     printf("Sorry, you must SET LINE or SET HOST first\n");
  453. #else
  454.     printf("Sorry, you must SET LINE first\n");
  455. #endif /* NETCONN */
  456.     return(0);
  457.     }
  458.     if (speed < 0L && network == 0 && ttfdflg == 0) {
  459.     printf("Sorry, you must SET SPEED first\n");
  460.     return(0);
  461.     }
  462. #ifdef TCPSOCKET
  463.     if (network && (nettype != NET_TCPB)
  464. #ifdef SUNX25
  465.         && (nettype != NET_SX25)
  466. #endif /* SUNX25 */
  467.     ) {
  468.     printf("Sorry, network type not supported\n");
  469.     return(0);
  470.     }
  471. #endif /* TCPSOCKET */
  472.  
  473.     if (ttyfd < 0) {            /* If communication device not open */
  474.     debug(F111,"ckucon opening",ttname,0); /* Open it now */
  475.     if (ttopen(ttname,
  476.            &local,
  477.            network ? -nettype : mdmtyp,
  478.            0
  479.            ) < 0) {
  480.         sprintf(temp,"Sorry, can't open %s",ttname);
  481.         perror(temp);
  482.         debug(F110,"ckucon open failure",temp,0);
  483.         return(0);
  484.     }
  485.     }
  486.     dohangup = 0;            /* Hangup not requested yet */
  487. #ifdef SUNX25
  488.     dox25clr = 0;            /* X.25 clear not requested yet */
  489. #endif /* SUNX25 */
  490.  
  491.     if (!quiet) {
  492. #ifdef NETCONN
  493.     if (network) {
  494.         printf("Connecting to host %s",ttname);
  495. #ifdef SUNX25
  496.         if (nettype == NET_SX25)
  497.           printf(", Link ID %d, LCN %d",linkid,lcn);
  498. #endif /* SUNX25 */
  499.     } else {
  500. #endif /* NETCONN */
  501.         printf("Connecting to %s",ttname);
  502.         if (speed > -1L) printf(", speed %ld",speed);
  503. #ifdef NETCONN
  504.     }
  505. #endif /* NETCONN */
  506.     printf(".\r\nThe escape character is Ctrl-%c (ASCII %d, %s)\r\n",
  507.            ctl(escape), escape, (escape == 127 ? "DEL" : ccntab[escape]));
  508.     printf("Type the escape character followed by C to get back,\r\n");
  509.     printf("or followed by ? to see other options.\r\n");
  510.     if (seslog) {
  511.         printf("(Session logged to %s, ",sesfil);
  512.         printf("%s)\r\n", sessft ? "binary" : "text");
  513.     }
  514.     if (debses) printf("Debugging Display...)\r\n");
  515.     fflush(stdout);
  516.     }
  517.  
  518. /* Condition console terminal and communication line */        
  519.  
  520.     if (conbin((char)escape) < 0) {
  521.     printf("Sorry, can't condition console terminal\n");
  522.     return(0);
  523.     }
  524.     debug(F101,"connect cmask","",cmask);
  525.     debug(F101,"connect cmdmsk","",cmdmsk);
  526.     goterr = 0;
  527.     if ((n = ttvt(speed,flow)) < 0) {    /* Enter "virtual terminal" mode */
  528.     debug(F101,"CONNECT ttvt","",n);
  529.     goterr = 1;            /* Error recovery... */
  530.     tthang();            /* Hang up and close the device. */
  531.     ttclos(0);
  532.     if (ttopen(ttname,        /* Open it again... */
  533.            &local,
  534.            network ? -nettype : mdmtyp,
  535.            0
  536.            ) < 0) {
  537.         sprintf(temp,"Sorry, can't reopen %s",ttname);
  538.         perror(temp);
  539.         return(0);
  540.     }
  541.     if (ttvt(speed,flow) < 0) {    /* Try virtual terminal mode again. */
  542.         conres();            /* Failure this time is fatal. */
  543.         printf("Sorry, Can't condition communication line\n");
  544.         return(0);
  545.     }
  546. #ifdef TNCODE
  547.     if (network && ttnproto == NP_TELNET)
  548.       tn_ini();            /* Just in case ttopen didn't... */
  549. #endif /* TNCODE */
  550.     }
  551.     debug(F101,"connect ttvt ok, escape","",escape);
  552.  
  553. #ifndef NOCSETS
  554. /* Set up character set translations */
  555.  
  556.     tcs = gettcs(tcsr,tcsl);        /* Get intermediate set. */
  557.  
  558.     if (tcsr == tcsl) {            /* Remote and local sets the same? */
  559.     sxo = rxo = NULL;        /* If so, no translation. */
  560.     sxi = rxi = NULL;
  561.     } else {                /* Otherwise, set up */
  562.     sxo = xls[tcs][tcsl];        /* translation function */
  563.     rxo = xlr[tcs][tcsr];        /* pointers for output functions */
  564.     sxi = xls[tcs][tcsr];        /* and for input functions. */
  565.     rxi = xlr[tcs][tcsl];
  566.     }
  567. /*
  568.   This is to prevent use of zmstuff() and zdstuff() by translation functions.
  569.   They only work with disk i/o, not with communication i/o.  Luckily Russian
  570.   translation functions don't do any stuffing...
  571. */
  572.     langsv = language;
  573. #ifndef NOCYRIL
  574.     if (language != L_RUSSIAN)
  575. #endif /* NOCYRIL */
  576.       language = L_USASCII;
  577.  
  578. #ifdef SKIPESC
  579. /*
  580.   We need to activate the "skip escape sequence" feature when:
  581.   (a) translation is elected, and
  582.   (b) the local and/or remote set is a 7-bit set other than US ASCII.
  583. */
  584.     skipesc = (tcs != TC_TRANSP) &&    /* Not transparent */
  585.       (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */
  586.     (fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */
  587.     inesc = ES_NORMAL;            /* Initial state of recognizer */
  588. #ifdef COMMENT
  589.     debug(F101,"tcs","",tcs);
  590.     debug(F101,"tcsl","",tcsl);
  591.     debug(F101,"tcsr","",tcsr);
  592.     debug(F101,"fcsinfo[tcsl].size","",fcsinfo[tcsl].size);
  593.     debug(F101,"fcsinfo[tcsr].size","",fcsinfo[tcsr].size);
  594. #endif /* COMMENT */
  595.     debug(F101,"skipesc","",skipesc);
  596. #endif /* SKIPESC */
  597. #endif /* NOCSETS */
  598.  
  599. /*
  600.   This is a label we jump back to when the lower fork sensed the need
  601.   to change modes.  As of 5A(178), this is used only by X.25 code
  602.   (perhaps unnecessarily? -- The X.25 code needs a lot of testing and
  603.   cleaning up...)
  604. */
  605. newfork:
  606.     debug(F100,"CONNECT newfork","",0);
  607.     parent_id = getpid();        /* Get parent id for signalling */
  608.     signal(SIGUSR1,SIG_IGN);        /* Don't kill myself */
  609. #ifdef SUNX25
  610.     pipe(padpipe);                      /* Create pipe to pass PAD parms */
  611. #endif /* SUNX25 */
  612.     pid = fork();            /* All ok, make a fork */
  613.     if (pid == (PID_T) -1) {        /* Can't create it. */
  614.     conres();            /* Reset the console. */
  615.     perror("Can't create keyboard fork");
  616.     if (!quiet) {
  617.     printf("\r\nCommunications disconnect (Back at %s)\r\n",
  618.            *myhost ?
  619.            myhost :
  620. #ifdef UNIX
  621.            "local UNIX system"
  622. #else
  623.            "local system"
  624. #endif /* UNIX */
  625.            );
  626.     }
  627.     printf("\n");
  628.     what = W_NOTHING;        /* So console modes are set right. */
  629. #ifndef NOCSETS
  630.     language = langsv;        /* Restore language */
  631. #endif /* NOCSETS */
  632.     parent_id = (PID_T) 0;        /* Clean up */
  633. #ifdef DYNAMIC
  634.     if (temp) free(temp);        /* Free allocated memory */
  635.     if (ibuf) free(ibuf);
  636.     if (obuf) free(obuf);
  637. #endif /* DYNAMIC */
  638.     return(1);
  639.     }
  640.     if (pid) {                /* Top fork reads, sends keystrokes */
  641. #ifdef NETCONN
  642. #ifdef SIGPIPE
  643.     /* SIGPIPE is raised if a process sends on a broken stream */
  644.     /* (do it, but only once!) */
  645.     if (network && ! sigpiph)
  646.         sigpiph = signal(SIGPIPE, SIG_IGN);
  647. #endif /* SIGPIPE */
  648. #endif /* NETCONN */
  649.     what = W_CONNECT;        /* Keep track of what we're doing */
  650.     active = 1;
  651.     debug(F101,"CONNECT keyboard fork duplex","",duplex);
  652.  
  653.     /* Catch communication errors or mode changes in lower fork */
  654.  
  655.     if (setjmp(con_env) == 0) {    /* Normal entry... */
  656.         sjval = 0;            /* Initialize setjmp return code. */
  657.         signal(SIGUSR1,conn_int);    /* Routine for child process exit. */
  658.         signal(SIGUSR2,mode_chg);    /* Routine for mode change. */
  659. #ifdef SUNX25
  660.         if (network && nettype == NET_SX25) {
  661.         obufl = 0;
  662.         bzero (x25obuf,sizeof(x25obuf)) ;
  663.         }
  664. #endif /* SUNX25 */
  665.  
  666. /*
  667.   Here is the big loop that gets characters from the keyboard and sends them
  668.   out the communication device.  There are two components to the communication
  669.   path: the connection from the keyboard to C-Kermit, and from C-Kermit to
  670.   the remote computer.  The treatment of the 8th bit of keyboard characters 
  671.   is governed by SET COMMAND BYTESIZE (cmdmsk).  The treatment of the 8th bit
  672.   of characters sent to the remote is governed by SET TERMINAL BYTESIZE
  673.   (cmask).   This distinction was introduced in edit 5A(164).
  674. */
  675.         while (active) {
  676. #ifndef NOSETKEY
  677.         if (kmptr) {        /* Have current macro? */
  678.             debug(F100,"kmptr non NULL","",0);
  679.             if ((c = (CHAR) *kmptr++) == NUL) { /* Get char from it */
  680.             kmptr = NULL;    /* If no more chars,  */
  681.             debug(F100,"macro empty, continuing","",0);
  682.             continue;    /* reset pointer and continue */
  683.             }
  684.             debug(F000,"char from macro","",c);
  685.         } else            /* No macro... */
  686. #endif /* NOSETKEY */
  687.           c = congks(0);    /* Read from keyboard */
  688.  
  689.         debug(F101,"** KEYB","",c);
  690.  
  691.                 if (c == -1) {        /* If read() got an error... */
  692. #ifdef COMMENT
  693. /*
  694.  This seems to cause problems.  If read() returns -1, the signal has already
  695.  been delivered, and nothing will wake up the pause().
  696. */
  697.             pause();        /* Wait for transmitter to finish. */
  698. #else
  699. #ifdef A986
  700. /*
  701.   On Altos machines with Xenix 3.0, pressing DEL in connect mode brings us
  702.   here (reason unknown).  The console line discipline at this point has
  703.   intr = ^C.  The communications tty has intr = DEL but we get here after
  704.   pressing DEL on the keyboard, even when the remote system has been set not
  705.   to echo.  With A986 defined, we stay in the read loop and beep only if the
  706.   offending character is not DEL.
  707. */
  708.             if ((c & 127) != 127) conoc(BEL);
  709. #else
  710.             conoc(BEL);        /* Beep */
  711.             active = 0;        /* and terminate the read loop */
  712.             continue;
  713. #endif /* A986 */
  714. #endif /* COMMENT */
  715.         }
  716.         c &= cmdmsk;        /* Do any requested masking */
  717. #ifndef NOSETKEY
  718. /*
  719.   Note: kmptr is NULL if we got character c from the keyboard, and it is
  720.   not NULL if it came from a macro.  In the latter case, we must avoid
  721.   expanding it again.
  722. */
  723.         if (!kmptr && macrotab[c]) { /* Macro definition for c? */
  724.             kmptr = macrotab[c];     /* Yes, set up macro pointer */
  725.             continue;             /* and restart the loop, */
  726.         } else c = keymap[c];         /* else use single-char keymap */
  727. #endif /* NOSETKEY */
  728.         if (
  729. #ifndef NOSETKEY
  730.             !kmptr &&
  731. #endif /* NOSETKEY */
  732.             ((c & 0x7f) == escape)) { /* Escape character? */
  733.             debug(F000,"connect got escape","",c);
  734.             c = congks(0) & 0177; /* Got esc, get its arg */
  735.             /* No key mapping here */
  736.             doesc((char) c);    /* Now process it */
  737.  
  738.         } else {        /* It's not the escape character */
  739.             csave = c;        /* Save it before translation */
  740.                     /* for local echoing. */
  741. #ifndef NOCSETS
  742. #ifndef SKIPESC
  743.             /* Translate character sets */
  744.             if (sxo) c = (*sxo)(c); /* From local to intermediate. */
  745.             if (rxo) c = (*rxo)(c); /* From intermediate to remote. */
  746. #else
  747.             if (inesc == ES_NORMAL) { /* If not inside escape seq.. */
  748.             /* Translate character sets */
  749.             if (sxo) c = (*sxo)((char)c); /* Local-intermediate */
  750.             if (rxo) c = (*rxo)((char)c); /* Intermediate-remote */
  751.             }
  752.             if (skipesc) chkaes((char)c); /* Check escape seq status */
  753. #endif /* SKIPESC */
  754. #endif /* NOCSETS */
  755. /*
  756.  If Shift-In/Shift-Out is selected and we have a 7-bit connection,
  757.  handle shifting here.
  758. */
  759.             if (sosi) {             /* Shift-In/Out selected? */
  760.             if (cmask == 0177) { /* In 7-bit environment? */
  761.                 if (c & 0200) {          /* 8-bit character? */
  762.                 if (outshift == 0) { /* If not shifted, */
  763.                     ttoc(dopar(SO)); /* shift. */
  764.                     outshift = 1;
  765.                 }
  766.                 } else {
  767.                 if (outshift == 1) { /* 7-bit character */
  768.                     ttoc(dopar(SI)); /* If shifted, */
  769.                     outshift = 0;    /* unshift. */
  770.                 }
  771.                 }
  772.             }
  773.             if (c == SO) outshift = 1;   /* User typed SO */
  774.             if (c == SI) outshift = 0;   /* User typed SI */
  775.             }
  776.             c &= cmask;        /* Apply Kermit-to-host mask now. */
  777. #ifdef SUNX25
  778.                     if (network && nettype == NET_SX25) {
  779.                         if (padparms[PAD_ECHO]) {
  780.                             if (debses)
  781.                   conol(dbchr(c)) ;
  782.                             else
  783.                   if ((c != padparms[PAD_CHAR_DELETE_CHAR])   &&
  784.                   (c != padparms[PAD_BUFFER_DELETE_CHAR]) &&
  785.                   (c != padparms[PAD_BUFFER_DISPLAY_CHAR]))
  786.                                 conoc(c) ;
  787.                             if (seslog) logchar(c);
  788.                         }
  789.             if (c == CR && (padparms[PAD_LF_AFTER_CR] == 4 ||
  790.                     padparms[PAD_LF_AFTER_CR] == 5)) {
  791.                             if (debses)
  792.                   conol(dbchr(LF)) ;
  793.                             else
  794.                   conoc(LF) ;
  795.                             if (seslog) logchar(LF);
  796.                         }
  797.                         if (c == padparms[PAD_BREAK_CHARACTER])
  798.               breakact();
  799.                         else if (padparms[PAD_DATA_FORWARD_TIMEOUT]) {
  800.                             tosend = 1;
  801.                             x25obuf [obufl++] = c;
  802.                         } else if (((c == padparms[PAD_CHAR_DELETE_CHAR])  ||
  803.                     (c == padparms[PAD_BUFFER_DELETE_CHAR]) ||
  804.                     (c == padparms[PAD_BUFFER_DISPLAY_CHAR])) 
  805.                    && (padparms[PAD_EDITING]))
  806.               if (c == padparms[PAD_CHAR_DELETE_CHAR])
  807.                 if (obufl > 0) {
  808.                 conol("\b \b"); obufl--;
  809.                 } else {}
  810.               else if (c == padparms[PAD_BUFFER_DELETE_CHAR]) {
  811.                   conol ("\r\nPAD Buffer Deleted\r\n");
  812.                   obufl = 0;
  813.               }
  814.               else if (c == padparms[PAD_BUFFER_DISPLAY_CHAR]) {
  815.                   conol("\r\n");
  816.                   conol(x25obuf);
  817.                   conol("\r\n");
  818.               } else {} 
  819.                         else {
  820.                             x25obuf [obufl++] = c;
  821.                             if (obufl == MAXOX25) tosend = 1;
  822.                             else if (c == CR) tosend = 1;
  823.                         }
  824.                         if (tosend) 
  825.               if (ttol(x25obuf,obufl) < 0) {
  826.                   perror ("\r\nCan't send characters");
  827.                   active = 0;
  828.               } else {
  829.                   bzero (x25obuf,sizeof(x25obuf));
  830.                   obufl = 0;
  831.                   tosend = 0;
  832.               } else {};
  833.                     } else {
  834. #endif /* SUNX25 */ 
  835.  
  836. /* If we have a CR, handle CR/CRLF mapping... */
  837.  
  838.             if (c == '\015') {
  839.             if (tnlm    /* TERMINAL NEWLINE ON */
  840. #ifdef TNCODE                /* And for TELNET... */
  841.             || (network && ttnproto == NP_TELNET)
  842. #endif /* TNCODE */
  843.             ) {
  844.                 ttoc(dopar('\015'));    /* Send CR */
  845.                 if (duplex) conoc('\015');    /* Maybe echo CR */
  846. #ifdef TNCODE
  847.                 if (network && !tn_nlm && ttnproto == NP_TELNET)
  848.                   c = '\0';        /* Stuff NUL */
  849.                 else
  850. #endif /* TNCODE */
  851.                   c = '\012';    /* Stuff LF */
  852.                 csave = c;
  853.             }
  854.             }            /* Now process the LF or NUL... */
  855. #ifdef TNCODE
  856. /* If user types the 0xff character (TELNET IAC), it must be doubled. */
  857.             else
  858.               if (c == IAC && network && ttnproto == NP_TELNET) {
  859.                     /* Send one copy now */
  860.             ttoc((char)IAC); /* and the other one just below. */
  861.             }
  862. #endif /* TNCODE */
  863.  
  864.             /* Send the character */
  865.  
  866.             if (ttoc((char)dopar((CHAR) c)) > -1) {
  867.                 if (duplex) {    /* If half duplex, must echo */
  868.                 if (debses)
  869.                   conol(dbchr(csave)); /* the original char */
  870.                 else               /* not the translated one */
  871.                   conoc((char)csave);
  872.                 if (seslog) { /* And maybe log it too */
  873.                 c2 = csave;
  874.                 if (sessft == 0 && csave == '\r')
  875.                   c2 = '\n';
  876.                 logchar((char)c2);
  877.                 }
  878.             }
  879.                     } else {
  880.             perror("\r\nCan't send character");
  881.             active = 0;
  882.             }
  883. #ifdef SUNX25
  884.         } 
  885. #endif /* SUNX25 */
  886.         }
  887.         }
  888.     }                /* Come here on death of child */
  889.     debug(F100,"CONNECT killing port fork","",0);
  890.     kill(pid,9);            /* Done, kill inferior fork. */
  891.     wait((WAIT_T *)0);        /* Wait till gone. */
  892.     if (sjval == 1) {        /* Read error on comm device */
  893.         dohangup = 1;
  894. #ifdef NETCONN
  895.         if (network) {
  896.         ttclos(0);
  897. #ifdef SUNX25
  898.         if (nettype == NET_SX25) initpad();
  899. #endif /* SUNX25 */
  900.         }
  901. #endif /* NETCONN */
  902.     }
  903.     if (sjval == 2)            /* If it was a mode change, go back */
  904.       goto newfork;            /* and coordinate with other fork. */
  905.     conres();            /* Reset the console. */
  906.     if (dohangup > 0) {        /* If hangup requested, do that. */
  907. #ifndef NODIAL
  908.         if (dohangup > 1)        /* User asked for it */
  909.           if (mdmhup() < 1)        /* Maybe hang up via modem */
  910. #endif /* NODIAL */
  911.           tthang();            /* And make sure we don't hang up */
  912.         dohangup = 0;        /* again unless requested again. */
  913.     }
  914. #ifdef NETCONN
  915. #ifdef SIGPIPE
  916.     if (network && sigpiph)
  917.         (VOID) signal(SIGPIPE, sigpiph);
  918. #endif /* SIGPIPE */
  919. #endif /* NETCONN */
  920. #ifdef SUNX25
  921.     if (dox25clr) {            /* If X.25 clear requested */
  922.         x25clear();            /* do that. */
  923.         initpad();
  924.         dox25clr = 0;        /* But only once. */
  925.     }
  926. #endif /* SUNX25 */
  927.     if (quitnow) doexit(GOOD_EXIT,xitsta); /* Exit now if requested. */
  928.     if (!quiet)
  929.       printf("(Back at %s)", *myhost ? myhost : "local UNIX system");
  930.     printf("\n");
  931.     what = W_NOTHING;        /* So console modes set right. */
  932. #ifndef NOCSETS
  933.     language = langsv;        /* Restore language */
  934. #endif /* NOCSETS */
  935.     parent_id = (PID_T) 0;
  936. #ifdef DYNAMIC
  937.     if (temp) free(temp);        /* Free allocated memory */
  938.     if (ibuf) free(ibuf);
  939.     if (obuf) free(obuf);
  940. #endif /* DYNAMIC */
  941.     return(1);
  942.  
  943.     } else {                /* Inferior reads, prints port input */
  944.  
  945.     if (priv_can()) {        /* Cancel all privs */
  946.         printf("?setuid error - fatal\n");
  947.         doexit(BAD_EXIT,-1);
  948.     }
  949.     signal(SIGINT, SIG_IGN);    /* In case these haven't been */
  950.     signal(SIGQUIT, SIG_IGN);    /* inherited from above... */
  951.  
  952.     inshift = outshift = 0;        /* Initial SO/SI shift state. */
  953.     sleep(1);            /* Wait for parent's handler setup.  */
  954.     ibp = ibuf;            /* Initialize input buffering */
  955.     ibc = 0;            /* And output buffering. */
  956.     obp = obuf;
  957.     obc = 0;
  958.     debug(F100,"CONNECT starting port fork","",0);
  959.     while (1) {            /* Fresh read, wait for a character. */
  960. #ifdef SUNX25
  961.         if (network && (nettype == NET_SX25)) {
  962.         bzero(x25ibuf,sizeof(x25ibuf)) ;
  963.         if ((ibufl = ttxin(MAXIX25,x25ibuf)) < 0) {
  964.             if (ibufl == -2) {  /* PAD parms changes */
  965.             write(padpipe[1],padparms,MAXPADPARMS);
  966.             kill(parent_id,SIGUSR2);
  967.             } else {
  968.             if (!quiet)
  969.               printf("\r\nCommunications disconnect ");
  970.             kill(parent_id,SIGUSR1);
  971.             }
  972.             pause();
  973.         }
  974.         if (debses) {        /* Debugging output */
  975.             p = x25ibuf ;
  976.                         while (ibufl--) { c = *p++; conol(dbchr(c)); }
  977.         } else {
  978.             if (sosi
  979. #ifndef NOCSETS
  980.             || tcsl != tcsr
  981. #endif /* NOCSETS */
  982.             ) { /* Character at a time */
  983.             for (i = 1; i < ibufl; i++) {
  984.                 c = x25ibuf[i] & cmask;
  985.                 if (sosi) { /* Handle SI/SO */
  986.                 if (c == SO) {
  987.                     inshift = 1;
  988.                     continue;
  989.                 } else if (c == SI) {
  990.                     inshift = 0;
  991.                     continue;
  992.                 }
  993.                 if (inshift)
  994.                   c |= 0200;
  995.                 }
  996. #ifndef NOCSETS
  997. #ifndef SKIPESC
  998.             /* Translate character sets */
  999.             if (sxo) c = (*sxo)(c); /* From local to intermediate. */
  1000.             if (rxo) c = (*rxo)(c); /* From intermediate to remote. */
  1001.  
  1002. #else /* Skipping escape sequences... */
  1003.  
  1004.             if (inesc == ES_NORMAL) { /* If not inside escape seq.. */
  1005.             /* Translate character sets */
  1006.             if (sxo) c = (*sxo)(c); /* Local to intermediate. */
  1007.             if (rxo) c = (*rxo)(c); /* Intermediate to remote. */
  1008.             }
  1009.             if (skipesc) chkaes(c); /* Check escape sequence status */
  1010. #endif /* SKIPESC */
  1011. #endif /* NOCSETS */
  1012.                 c &= cmdmsk; /* Apply command mask. */
  1013.                 conoc(c);    /* Output to screen */
  1014.                 logchar(c);  /* and session log */
  1015.             }
  1016.             } else {         /* All at once */
  1017.             for (i = 1; i < ibufl; i++)
  1018.               x25ibuf[i] &= (cmask & cmdmsk);
  1019.             conxo(ibufl,x25ibuf);
  1020.             if (seslog) zsoutx(ZSFILE,x25ibuf,ibufl);
  1021.             }
  1022.         }
  1023.         continue;
  1024.  
  1025.         } else {            /* Not X.25... */
  1026. #endif /* SUNX25 */
  1027. /*
  1028.   Get the next communication line character from our internal buffer.
  1029.   If the buffer is empty, refill it.
  1030. */
  1031.         c = ckcgetc(0);        /* Get next character */
  1032.         /* debug(F101,"CONNECT c","",c); */
  1033.         if (c < 0) {
  1034.             if (!quiet) {    /* Failed... */
  1035.             printf("\r\nCommunications disconnect ");
  1036.             if ( c == -3
  1037. #ifdef ultrix
  1038. /* This happens on Ultrix if there's no carrier */
  1039.                 && errno != EIO
  1040. #endif /* ultrix */
  1041. #ifdef UTEK
  1042. /* This happens on UTEK if there's no carrier */
  1043.                 && errno != EWOULDBLOCK
  1044. #endif /* UTEK */
  1045.                 )
  1046.               perror("\r\nCan't read character");
  1047.             }
  1048. #ifdef NOSETBUF
  1049.             fflush(stdout);
  1050. #endif /* NOSETBUF */
  1051.             tthang();        /* Hang up the connection */
  1052.             kill(parent_id,SIGUSR1); /* Notify parent */
  1053.             for (;;) pause();    /* and wait to be killed */
  1054.         }
  1055.         debug(F101,"** PORT","",c);
  1056. #ifdef TNCODE
  1057.         /* Handle TELNET negotiations here */    
  1058.         if (c == IAC && network && ttnproto == NP_TELNET) {
  1059.             ckcputf();        /* Dump output buffer */
  1060.             if ((tx = tn_doop((CHAR)(c & 0xff),duplex,ckcgetc)) == 0) {
  1061.             continue;
  1062.             } else if (tx == -1) { /* I/O error */
  1063.             if (!quiet)
  1064.               printf("\r\nCommunications disconnect ");
  1065. #ifdef NOSETBUF
  1066.             fflush(stdout);
  1067. #endif /* NOSETBUF */
  1068.             kill(parent_id,SIGUSR1); /* Notify parent. */
  1069.             for (;;) pause(); /* Wait to be killed. */
  1070.             } else if ((tx == 1) && (!duplex)) { /* ECHO change */
  1071.             kill(parent_id,SIGUSR2); /* Tell the parent fork */
  1072.             duplex = 1;
  1073.             } else if ((tx == 2) && (duplex)) { /* ECHO change */
  1074.             kill(parent_id,SIGUSR2); 
  1075.             duplex = 0;
  1076.             } else if (tx == 3) { /* Quoted IAC */
  1077.             c = 255;
  1078.             } else continue;    /* Negotiation OK, get next char. */
  1079.         }
  1080. #endif /* TNCODE */
  1081.         if (debses) {        /* Output character to screen */
  1082.             char *s;        /* Debugging display... */
  1083.             s = dbchr(c);
  1084.             while (*s)
  1085.               ckcputc(*s++);
  1086.         } else {        /* Regular display ... */
  1087.             c &= cmask;        /* Apply Kermit-to-remote mask */
  1088.             if (sosi) {        /* Handle SI/SO */
  1089.             if (c == SO) {    /* Shift Out */
  1090.                 inshift = 1;
  1091.                 continue;
  1092.             } else if (c == SI) { /* Shift In */
  1093.                 inshift = 0;
  1094.                 continue;
  1095.             }
  1096.             if (inshift) c |= 0200; 
  1097.             }
  1098. #ifndef NOCSETS
  1099. #ifndef SKIPESC
  1100.             /* Translate character sets */
  1101.             if (sxi) c = (*sxi)((CHAR)c);
  1102.             if (rxi) c = (*rxi)((CHAR)c);
  1103. #else
  1104.             if (inesc == ES_NORMAL) {
  1105.             /* Translate character sets */
  1106.             if (sxi) c = (*sxi)((CHAR)c);
  1107.             if (rxi) c = (*rxi)((CHAR)c);
  1108.             }
  1109.             /* Adjust escape sequence status */
  1110.             if (skipesc) chkaes((char)c);
  1111. #endif /* SKIPESC */
  1112. #endif /* NOCSETS */
  1113.             c &= cmdmsk;    /* Apply command mask. */
  1114.             if (c == CR && tt_crd) { /* SET TERM CR-DISPLAY CRLF ? */
  1115.             ckcputc(c);         /* Yes, output CR */
  1116.             if (seslog) logchar((char)c);
  1117.             c = LF;             /* and insert a linefeed */
  1118.             }
  1119.             ckcputc(c);        /* Output character to screen */
  1120.             if (seslog) logchar((char)c); /* Do session log */
  1121.         }
  1122. #ifdef SUNX25
  1123.         }   
  1124. #endif /* SUNX25 */    
  1125.     }
  1126.     }
  1127. }
  1128.  
  1129.  
  1130. /*  H C O N N E  --  Give help message for connect.  */
  1131.  
  1132. int
  1133. hconne() {
  1134.     int c;
  1135.     static char *hlpmsg[] = {
  1136. "\r\n  ? for this message",
  1137. "\r\n  0 (zero) to send a null",
  1138. "\r\n  B to send a BREAK",
  1139. #ifdef CK_LBRK
  1140. "\r\n  L to send a Long BREAK",
  1141. #endif /* CK_LBRK */
  1142. #ifdef NETCONN
  1143. "\r\n  I to send a network interrupt packet",
  1144. #ifdef TCPSOCKET
  1145. "\r\n  A to send Are You There?",
  1146. #endif /* TCPSOCKET */
  1147. #ifdef SUNX25
  1148. "\r\n  R to reset X.25 virtual circuit",
  1149. #endif /* SUNX25 */
  1150. #endif /* NETCONN */
  1151. "\r\n  H to hangup and close the connection",
  1152. "\r\n  Q to hangup and quit Kermit",
  1153. "\r\n  S for status",
  1154. "\r\n  ! to push to local shell",
  1155. "\r\n  Z to suspend",
  1156. "\r\n  \\ backslash code:",
  1157. "\r\n    \\nnn  decimal character code",
  1158. "\r\n    \\Onnn octal character code",
  1159. "\r\n    \\Xhh  hexadecimal character code",
  1160. "\r\n    terminate with carriage return.",
  1161. "\r\n Type the escape character again to send the escape character, or",
  1162. "\r\n press the space-bar to resume the CONNECT command.\r\n\r\n",
  1163. "" };
  1164.     conol("\r\nPress C to return to ");
  1165.     conol(*myhost ? myhost : "the C-Kermit prompt");
  1166.     conol(", or:");
  1167.     conola(hlpmsg);            /* Print the help message. */
  1168.     conol("Command>");            /* Prompt for command. */
  1169.     c = congks(0) & 0177;        /* Get character, strip any parity. */
  1170.     /* No key mapping or translation here */
  1171.     if (c != CMDQ)
  1172.       conoll("");
  1173.     return(c);                /* Return it. */
  1174. }
  1175.  
  1176.  
  1177. /*  D O E S C  --  Process an escape character argument  */
  1178.  
  1179. VOID
  1180. #ifdef CK_ANSIC
  1181. doesc(char c)
  1182. #else
  1183. doesc(c) char c;
  1184. #endif /* CK_ANSIC */
  1185. /* doesc */ {
  1186.     CHAR d;
  1187.   
  1188.     while (1) {
  1189.     if (c == escape) {        /* Send escape character */
  1190.         d = dopar((CHAR) c); ttoc((char) d); return;
  1191.         } else                /* Or else look it up below. */
  1192.         if (isupper(c)) c = tolower(c);
  1193.  
  1194.     switch(c) {
  1195.  
  1196.     case 'c':            /* Escape back to prompt */
  1197.     case '\03':
  1198.         active = 0; conol("\r\n"); return;
  1199.  
  1200.     case 'b':            /* Send a BREAK signal */
  1201.     case '\02':
  1202.         ttsndb(); return;
  1203.  
  1204. #ifdef NETCONN
  1205.     case 'i':            /* Send Interrupt */
  1206.     case '\011':
  1207. #ifdef TCPSOCKET
  1208. #ifndef IP
  1209. #define IP 244
  1210. #endif /* IP */
  1211.         if (network && ttnproto == NP_TELNET) { /* TELNET */
  1212.         temp[0] = (CHAR) IAC;    /* I Am a Command */
  1213.         temp[1] = (CHAR) IP;    /* Interrupt Process */
  1214.         temp[2] = NUL;
  1215.         ttol((CHAR *)temp,2);
  1216.         } else 
  1217. #endif /* TCPSOCKET */
  1218. #ifdef SUNX25
  1219.             if (network && (nettype == NET_SX25)) { /* X.25 */
  1220.         (VOID) x25intr(0);                /* X.25 interrupt packet */
  1221.         conol("\r\n");
  1222.         } else
  1223. #endif /* SUNX25 */
  1224.           conoc(BEL);
  1225.         return;
  1226.  
  1227. #ifdef TCPSOCKET
  1228.     case 'a':            /* "Are You There?" */
  1229.     case '\01':
  1230. #ifndef AYT
  1231. #define AYT 246
  1232. #endif /* AYT */
  1233.         if (network && ttnproto == NP_TELNET) {
  1234.         temp[0] = (CHAR) IAC;    /* I Am a Command */
  1235.         temp[1] = (CHAR) AYT;    /* Are You There? */
  1236.         temp[2] = NUL;
  1237.         ttol((CHAR *)temp,2);
  1238.         } else conoc(BEL);
  1239.         return;
  1240. #endif /* TCPSOCKET */
  1241. #endif /* NETCONN */
  1242.  
  1243. #ifdef CK_LBRK
  1244.     case 'l':            /* Send a Long BREAK signal */
  1245.         ttsndlb(); return;
  1246. #endif /* CK_LBRK */
  1247.  
  1248.     case 'h':            /* Hangup */
  1249.      /*    case '\010': */            /* No, too dangerous */
  1250. #ifdef SUNX25
  1251.             if (network && (nettype == NET_SX25)) dox25clr = 1;
  1252.             else
  1253. #endif /* SUNX25 */
  1254.         dohangup = 2; active = 0; conol("\r\nHanging up "); return;
  1255.  
  1256. #ifdef SUNX25
  1257.         case 'r':                       /* Reset the X.25 virtual circuit */
  1258.         case '\022':
  1259.             if (network && (nettype == NET_SX25)) (VOID) x25reset();
  1260.             conol("\r\n"); return;
  1261. #endif /* SUNX25 */
  1262.  
  1263.     case 'q':            /* Quit */
  1264.         dohangup = 2; quitnow = 1; active = 0; conol("\r\n"); return;
  1265.  
  1266.     case 's':            /* Status */
  1267.         sprintf(temp,
  1268.             "\r\nConnected %s %s", network ? "to" : "through", ttname);
  1269.         conol(temp);
  1270. #ifdef SUNX25
  1271.             if (network && (nettype == NET_SX25)) {
  1272.                 sprintf(temp,", Link ID %d, LCN %d",linkid,lcn); conol(temp);
  1273.         }
  1274. #endif /* SUNX25 */
  1275.         if (speed >= 0L) {
  1276.         sprintf(temp,", speed %ld", speed);
  1277.         conoll(temp);
  1278.         } else conoll("");
  1279.         sprintf(temp,
  1280.             "Terminal bytesize: %d, Command bytesize: %d, Parity: ",
  1281.             (cmask  == 0177) ? 7 : 8,
  1282.             (cmdmsk == 0177) ? 7 : 8 );
  1283.         conol(temp);
  1284.  
  1285.         switch (parity) {
  1286.           case  0:  conoll("none");  break;
  1287.           case 'e': conoll("even");  break;
  1288.           case 'o': conoll("odd");   break;
  1289.           case 's': conoll("space"); break;
  1290.           case 'm': conoll("mark");  break;
  1291.         }
  1292.         sprintf(temp,"Terminal echo: %s", duplex ? "local" : "remote");
  1293.         conoll(temp);
  1294.         if (seslog) {
  1295.         conol("Logging to: "); conoll(sesfil);
  1296.             }
  1297.         if (!network) shomdm();
  1298.         return;
  1299.  
  1300.     case '?':            /* Help */
  1301.         c = hconne(); continue;
  1302.  
  1303.     case '0':            /* Send a null */
  1304.         c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return;
  1305.  
  1306. #ifndef NOPUSH
  1307.     case 'z': case '\032':        /* Suspend */
  1308.         stptrap(0); return;
  1309.  
  1310.     case '@':            /* Start inferior command processor */
  1311.     case '!':
  1312.         conres();            /* Put console back to normal */
  1313.         zshcmd("");            /* Fork a shell. */
  1314.         if (conbin((char)escape) < 0) {
  1315.         printf("Error resuming CONNECT session\n");
  1316.         active = 0;
  1317.         }
  1318.         return;
  1319. #endif /* NOPUSH */
  1320.  
  1321.     case SP:            /* Space, ignore */
  1322.         return;
  1323.  
  1324.     default:            /* Other */
  1325.         if (c == CMDQ) {        /* Backslash escape */
  1326.         int x;
  1327.         kbp = kbuf;
  1328.         *kbp++ = c;
  1329.         while (((c = (congks(0) & cmdmsk)) != '\r') && (c != '\n'))
  1330.           *kbp++ = c;
  1331.         *kbp = NUL; kbp = kbuf;
  1332.         x = xxesc(&kbp);    /* Interpret it */
  1333.         if (x >= 0) {        /* No key mapping here */
  1334.             c = dopar((CHAR) x);
  1335.             ttoc((char) c);
  1336.             return;
  1337.         } else {        /* Invalid backslash code. */
  1338.             conoc(BEL);
  1339.             return;
  1340.         }
  1341.         }
  1342.         conoc(BEL); return;     /* Invalid esc arg, beep */
  1343.         }
  1344.     }
  1345. }
  1346.  
  1347. VOID
  1348. #ifdef CK_ANSIC
  1349. logchar(char c)
  1350. #else
  1351. logchar(c) char c;
  1352. #endif /* CK_ANSIC */
  1353. /* logchar */ {            /* Log character c to session log */
  1354.     if (seslog) 
  1355.       if ((sessft != 0) ||
  1356.       (c != '\r' &&
  1357.        c != '\0' &&
  1358.        c != XON &&
  1359.        c != XOFF))
  1360.     if (zchout(ZSFILE,c) < 0) {
  1361.         conoll("");
  1362.         conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
  1363.         seslog = 0;
  1364.     }
  1365. }
  1366.